home *** CD-ROM | disk | FTP | other *** search
/ EnigmA Amiga Run 1995 October / EnigmA AMIGA RUN 01 (1995)(G.R. Edizioni)(IT)[!][issue 1995-10][Aminet 7].iso / Aminet / comm / tcp / wu_ftpd_37_21.lha / wu-ftpd / src / access.c next >
C/C++ Source or Header  |  1994-08-08  |  25KB  |  848 lines

  1. /* Copyright (c) 1993, 1994  Washington University in Saint Louis
  2.  * All rights reserved.
  3.  *
  4.  * Redistribution and use in source and binary forms, with or without
  5.  * modification, are permitted provided that the following conditions are
  6.  * met: 1. Redistributions of source code must retain the above copyright
  7.  * notice, this list of conditions and the following disclaimer. 2.
  8.  * Redistributions in binary form must reproduce the above copyright notice,
  9.  * this list of conditions and the following disclaimer in the documentation
  10.  * and/or other materials provided with the distribution. 3. All advertising
  11.  * materials mentioning features or use of this software must display the
  12.  * following acknowledgement: This product includes software developed by the
  13.  * Washington University in Saint Louis and its contributors. 4. Neither the
  14.  * name of the University nor the names of its contributors may be used to
  15.  * endorse or promote products derived from this software without specific
  16.  * prior written permission.
  17.  *
  18.  * THIS SOFTWARE IS PROVIDED BY WASHINGTON UNIVERSITY AND CONTRIBUTORS
  19.  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  20.  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  21.  * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL WASHINGTON
  22.  * UNIVERSITY OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
  23.  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
  24.  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  25.  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  26.  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  27.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
  28.  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  29.  * POSSIBILITY OF SUCH DAMAGE.
  30.  */
  31.  
  32. #include "config.h"
  33.  
  34. #include <stdio.h>
  35. #include <errno.h>
  36. #include <string.h>
  37. #ifdef SYSSYSLOG
  38. #include <sys/syslog.h>
  39. #else
  40. #include <syslog.h>
  41. #endif
  42. #include <time.h>
  43. #include <ctype.h>
  44. #include <pwd.h>
  45. #include <grp.h>
  46.  
  47. #include <sys/types.h>
  48. #include <sys/stat.h>
  49. #include <sys/file.h>
  50. #include <sys/param.h>
  51.  
  52. #include "pathnames.h"
  53. #include "extensions.h"
  54.  
  55. #if defined(SVR4) || defined(ISC) || defined(AMIGA)
  56. #include <fcntl.h>
  57. #endif
  58.  
  59. extern char remotehost[],
  60.   remoteaddr[],
  61.  *aclbuf;
  62. extern int nameserved,
  63.   anonymous,
  64.   guest,
  65.   use_accessfile;
  66. char Shutdown[MAXPATHLEN];
  67. #define MAXLINE    80
  68. static  char  incline[MAXLINE];
  69. int pidfd = -1;
  70.  
  71. extern int fnmatch();
  72.  
  73. /*************************************************************************/
  74. /* FUNCTION  : parse_time                                                */
  75. /* PURPOSE   : Check a single valid-time-string against the current time */
  76. /*             and return whether or not a match occurs.                 */
  77. /* ARGUMENTS : a pointer to the time-string                              */
  78. /*************************************************************************/
  79.  
  80. int
  81. parsetime(char *whattime)
  82. {
  83.     static char *days[] = {"Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Wk"};
  84.     time_t clock;
  85.     struct tm *curtime;
  86.     int wday,
  87.       start,
  88.       stop,
  89.       ltime,
  90.       validday,
  91.       loop,
  92.       match;
  93.  
  94.     (void) time(&clock);
  95.     curtime = localtime(&clock);
  96.     wday = curtime->tm_wday;
  97.     validday = 0;
  98.     match = 1;
  99.  
  100.     while (match && isalpha(*whattime) && isupper(*whattime)) {
  101.         match = 0;
  102.         for (loop = 0; loop < 8; loop++) {
  103.             if (strncmp(days[loop], whattime, 2) == NULL) {
  104.                 whattime += 2;
  105.                 match = 1;
  106.                 if ((wday == loop) | ((loop == 7) && wday && (wday < 6))) {
  107.                     validday = 1;
  108.                 }
  109.             }
  110.         }
  111.     }
  112.  
  113.     if (strncmp(whattime, "Any", 3) == NULL) {
  114.         validday = 1;
  115.         whattime += 3;
  116.     }
  117.     if (!validday)
  118.         return (0);
  119.  
  120.     if (sscanf(whattime, "%d-%d", &start, &stop) == 2) {
  121.         ltime = curtime->tm_min + 100 * curtime->tm_hour;
  122.         if ((start < stop) && ((ltime > start) && ltime < stop))
  123.             return (1);
  124.         if ((start > stop) && ((ltime > start) || ltime < stop))
  125.             return (1);
  126.     } else
  127.         return (1);
  128.  
  129.     return (0);
  130. }
  131.  
  132. /*************************************************************************/
  133. /* FUNCTION  : validtime                                                 */
  134. /* PURPOSE   : Break apart a set of valid time-strings and pass them to  */
  135. /*             parse_time, returning whether or not ANY matches occurred */
  136. /* ARGUMENTS : a pointer to the time-string                              */
  137. /*************************************************************************/
  138.  
  139. int
  140. validtime(char *ptr)
  141. {
  142.     char *nextptr;
  143.     int good;
  144.  
  145.     while (1) {
  146.         nextptr = strchr(ptr, '|');
  147.         if (strchr(ptr, '|') == NULL)
  148.             return (parsetime(ptr));
  149.         *nextptr = '\0';
  150.         good = parsetime(ptr);
  151.         /* gotta restore the | or things get skipped! */
  152.         *nextptr++ = '|';
  153.         if (good)
  154.             return (1);
  155.         ptr = nextptr;
  156.     }
  157. }
  158.  
  159. /*************************************************************************/
  160. /* FUNCTION  : hostmatch                                                 */
  161. /* PURPOSE   : Match remote hostname or address against a glob string    */
  162. /* ARGUMENTS : The string to match                                       */
  163. /* RETURNS   : 0 if no match, 1 if a match occurs                        */
  164. /*************************************************************************/
  165.  
  166. hostmatch(char *addr)
  167. {
  168.     FILE  *incfile;
  169.     char  *ptr;
  170.     int   found = 0;
  171.  
  172.     if (addr == NULL) return(0);
  173.  
  174.     if (isdigit(*addr))
  175.         return(fnmatch(addr, remoteaddr, NULL));
  176.     else if (*addr == '/') {
  177.         /*
  178.          * read addrglobs from named path using similar format as addrglobs
  179.          * in access file
  180.          */
  181.         if ((incfile = fopen(addr, "r")) == NULL) {
  182.             if (errno != ENOENT) syslog(LOG_ERR,
  183.                 "cannot open addrglob file %s: %s", addr, strerror(errno));
  184.             return(0);
  185.         }
  186.         
  187.         while (!found && (fgets(incline, MAXLINE, incfile) != NULL)) {
  188.             ptr = strtok(incline, " \t\n");
  189.             if (ptr && hostmatch(ptr))
  190.                 found = 1;
  191.             while (!found && ((ptr = strtok(NULL, " \t\n")) != NULL)) {
  192.                 if (ptr && hostmatch(ptr))
  193.                     found = 1;
  194.             }
  195.         }
  196.         fclose(incfile);
  197.         return(found);
  198.     }
  199.     else
  200.         return(fnmatch(addr, remotehost, FNM_NOCASE));
  201. }
  202.  
  203. /*************************************************************************/
  204. /* FUNCTION  : acl_guestgroup                                            */
  205. /* PURPOSE   : If the real user is a member of any of the listed groups, */
  206. /*             return 1.  Otherwise return 0.                            */
  207. /* ARGUMENTS : pw, a pointer to the passwd struct for the user           */
  208. /*************************************************************************/
  209.  
  210. int
  211. acl_guestgroup(struct passwd *pw)
  212. {
  213.     struct aclmember *entry = NULL;
  214.     struct group *grp;
  215.     int which;
  216.     char **member;
  217.  
  218.     entry = (struct aclmember *) NULL;
  219.     /* guestgroup <group> [<group> ...] */
  220.  
  221.     while (getaclentry("guestgroup", &entry)) {
  222.         for (which = 0; (which < MAXARGS) && ARG[which]; which++) {
  223.             if (!(grp = getgrnam(ARG[which])))
  224.                 continue;
  225.             if (pw->pw_gid == grp->gr_gid)
  226.                 return (1);
  227.             for (member = grp->gr_mem; *member; member++) {
  228.                 if (!strcmp(*member, pw->pw_name))
  229.                     return (1);
  230.             }
  231.         }
  232.     }
  233.     return (0);
  234. }
  235.  
  236. /*************************************************************************/
  237. /* FUNCTION  : acl_autogroup                                             */
  238. /* PURPOSE   : If the guest user is a member of any of the classes in    */
  239. /*             the autogroup comment, cause a setegid() to the specified */
  240. /*             group.                                                    */
  241. /* ARGUMENTS : pw, a pointer to the passwd struct for the user           */
  242. /*************************************************************************/
  243.  
  244. void
  245. acl_autogroup(struct passwd *pw)
  246. {
  247.     char class[1024];
  248.  
  249.     struct aclmember *entry = NULL;
  250.     struct group *grp;
  251.     gid_t gid;
  252.     int which;
  253.  
  254.     (void) acl_getclass(class);
  255.  
  256.     entry = (struct aclmember *) NULL;
  257.     /* autogroup <group> <class> [<class> ...] */
  258.  
  259.     while (getaclentry("autogroup", &entry)) {
  260.         if (!ARG0 || !ARG1)
  261.             return;
  262.  
  263.         grp = getgrnam(ARG0);
  264.         if (grp) {
  265.             gid = grp->gr_gid;
  266.         } else {
  267.             syslog(LOG_ERR, "autogroup: set group %s not found", ARG0);
  268.             continue;
  269.         }
  270.  
  271.         for (which = 1; (which < MAXARGS) && ARG[which]; which++) {
  272.             if (!strcmp(ARG[which], class)) {
  273.                 pw->pw_gid = gid;
  274.                 return;
  275.             }
  276.         }
  277.     }
  278. }
  279.  
  280. /*************************************************************************/
  281. /* FUNCTION  : acl_setfunctions                                          */
  282. /* PURPOSE   : Scan the ACL buffer and determine what logging to perform */
  283. /*             for this user, and whether or not user is allowed to use  */
  284. /*             the automatic TAR and COMPRESS functions.                 */
  285. /* ARGUMENTS : pointer to buffer to class name, pointer to ACL buffer    */
  286. /*************************************************************************/
  287.  
  288. void
  289. acl_setfunctions(void)
  290. {
  291.     char class[1024];
  292.  
  293.     extern int log_incoming_xfers,
  294.       log_outbound_xfers,
  295.       mangleopts,
  296.       log_commands,
  297.       lgi_failure_threshold;
  298.  
  299.     struct aclmember *entry = NULL;
  300.  
  301.     int l_compress = 0,
  302.       l_tar = 0,
  303.       inbound = 0,
  304.       outbound = 0,
  305.       which,
  306.       set;
  307.  
  308.     log_incoming_xfers = 0;
  309.     log_outbound_xfers = 0;
  310.     log_commands = 0;
  311.  
  312.     (void) acl_getclass(class);
  313.  
  314.     entry = (struct aclmember *) NULL;
  315.     if (getaclentry("loginfails", &entry) && ARG0 != NULL) {
  316.         lgi_failure_threshold = atoi(ARG0);
  317.     }
  318. #ifndef NO_PRIVATE
  319.     entry = (struct aclmember *) NULL;
  320.     if (getaclentry("private", &entry) && !strcmp(ARG0, "yes"))
  321.         priv_setup(_PATH_PRIVATE);
  322. #endif /* !NO_PRIVATE */
  323.  
  324.     entry = (struct aclmember *) NULL;
  325.     set = 0;
  326.     while (!set && getaclentry("compress", &entry)) {
  327.         if (!strcasecmp(ARG0, "yes"))
  328.             l_compress = 1;
  329.         for (which = 1; (which < MAXARGS) && ARG[which]; which++) {
  330.             if (fnmatch(ARG[which], class, NULL)) {
  331.                 mangleopts |= l_compress * (O_COMPRESS | O_UNCOMPRESS);
  332.                 set = 1;
  333.             }
  334.         }
  335.     }
  336.  
  337.     entry = (struct aclmember *) NULL;
  338.     set = 0;
  339.     while (!set && getaclentry("tar", &entry)) {
  340.         if (!strcasecmp(ARG0, "yes"))
  341.             l_tar = 1;
  342.         for (which = 1; (which < MAXARGS) && ARG[which]; which++) {
  343.             if (fnmatch(ARG[which], class, NULL)) {
  344.                 mangleopts |= l_tar * O_TAR;
  345.                 set = 1;
  346.             }
  347.         }
  348.     }
  349.  
  350.     /* plan on expanding command syntax to include classes for each of these */
  351.  
  352.     entry = (struct aclmember *) NULL;
  353.     while (getaclentry("log", &entry)) {
  354.         if (!strcasecmp(ARG0, "commands")) {
  355.             if (anonymous && strcasestr(ARG1, "anonymous"))
  356.                 log_commands = 1;
  357.             if (guest && strcasestr(ARG1, "guest"))
  358.                 log_commands = 1;
  359.             if (!guest && !anonymous && strcasestr(ARG1, "real"))
  360.                 log_commands = 1;
  361.         }
  362.         if (!strcasecmp(ARG0, "transfers")) {
  363.             set = 0;
  364.             if (strcasestr(ARG1, "anonymous") && anonymous)
  365.                 set = 1;
  366.             if (strcasestr(ARG1, "guest") && guest)
  367.                 set = 1;
  368.             if (strcasestr(ARG1, "real") && !guest && !anonymous)
  369.                 set = 1;
  370.             if (strcasestr(ARG2, "inbound"))
  371.                 inbound = 1;
  372.             if (strcasestr(ARG2, "outbound"))
  373.                 outbound = 1;
  374.             if (set)
  375.                 log_incoming_xfers = inbound;
  376.             if (set)
  377.                 log_outbound_xfers = outbound;
  378.         }
  379.     }
  380. }
  381.  
  382. /*************************************************************************/
  383. /* FUNCTION  : acl_getclass                                              */
  384. /* PURPOSE   : Scan the ACL buffer and determine what class user is in   */
  385. /* ARGUMENTS : pointer to buffer to class name, pointer to ACL buffer    */
  386. /*************************************************************************/
  387.  
  388. int
  389. acl_getclass(char *classbuf)
  390. {
  391.     int which;
  392.     struct aclmember *entry = NULL;
  393.  
  394.     while (getaclentry("class", &entry)) {
  395.         if (ARG0)
  396.             strcpy(classbuf, ARG0);
  397.  
  398.         for (which = 2; (which < MAXARGS) && ARG[which]; which++) {
  399.             if (anonymous && strcasestr(ARG1, "anonymous") &&
  400.                 hostmatch(ARG[which]))
  401.                 return (1);
  402.  
  403.             if (guest && strcasestr(ARG1, "guest") && hostmatch(ARG[which]))
  404.                 return (1);
  405.  
  406.             if (!guest && !anonymous && strcasestr(ARG1, "real") &&
  407.                 hostmatch(ARG[which]))
  408.                 return (1);
  409.         }
  410.     }
  411.  
  412.     *classbuf = (char) NULL;
  413.     return (0);
  414.  
  415. }
  416.  
  417. /*************************************************************************/
  418. /* FUNCTION  : acl_getlimit                                              */
  419. /* PURPOSE   : Scan the ACL buffer and determine what limit applies to   */
  420. /*             the user                                                  */
  421. /* ARGUMENTS : pointer class name, pointer to ACL buffer                 */
  422. /*************************************************************************/
  423.  
  424. int
  425. acl_getlimit(char *class, char *msgpathbuf)
  426. {
  427.     int limit;
  428.     struct aclmember *entry = NULL;
  429.  
  430.     if (msgpathbuf)
  431.         *msgpathbuf = NULL;
  432.  
  433.     /* limit <class> <n> <times> [<message_file>] */
  434.     while (getaclentry("limit", &entry)) {
  435.         if (!ARG0 || !ARG1 || !ARG2)
  436.             continue;
  437.         if (!strcmp(class, ARG0)) {
  438.             limit = atoi(ARG1);
  439.             if (validtime(ARG2)) {
  440.                 if (ARG3 && msgpathbuf)
  441.                     strcpy(msgpathbuf, ARG3);
  442.                 return (limit);
  443.             }
  444.         }
  445.     }
  446.     return (-1);
  447. }
  448.  
  449. /*************************************************************************/
  450. /* FUNCTION  : acl_deny                                                  */
  451. /* PURPOSE   : Scan the ACL buffer and determine a deny command applies  */
  452. /* ARGUMENTS : pointer class name, pointer to ACL buffer                 */
  453. /*************************************************************************/
  454.  
  455. int
  456. acl_deny(char *msgpathbuf)
  457. {
  458.     struct aclmember *entry = NULL;
  459.  
  460.     if (msgpathbuf)
  461.         *msgpathbuf = (char) NULL;
  462.  
  463.     /* deny <addrglob> [<message_file>] */
  464.     while (getaclentry("deny", &entry)) {
  465.         if (!ARG0)
  466.             continue;
  467.         if (!nameserved && !strcmp(ARG0, "!nameserved")) {
  468.             if (ARG1)
  469.                 strcpy(msgpathbuf, entry->arg[1]);
  470.             return (1);
  471.         }
  472.         if (hostmatch(ARG0)) {
  473.             if (ARG1)
  474.                 strcpy(msgpathbuf, entry->arg[1]);
  475.             return (1);
  476.         }
  477.     }
  478.     return (0);
  479. }
  480.  
  481. /*************************************************************************/
  482. /* FUNCTION  : acl_countusers                                            */
  483. /* PURPOSE   : Check the anonymous FTP access lists to see if this       */
  484. /*             access is permitted.                                      */
  485. /* ARGUMENTS : none                                                      */
  486. /*************************************************************************/
  487.  
  488. int
  489. acl_countusers(char *class)
  490. {
  491.     int count,
  492.       which;
  493.     char pidfile[MAXPATHLEN];
  494.     pid_t buf[MAXUSERS];
  495. #if !defined(HAVE_FLOCK) && !defined(AMIGA)
  496. struct flock arg;
  497. #endif
  498.  
  499.     /* 
  500.      * if pidfd was not opened previously... 
  501.      * pidfd must stay open after the chroot(~ftp)  
  502.      */
  503.  
  504.     sprintf(pidfile, _PATH_PIDNAMES, class);
  505.  
  506.     if (pidfd < 0) {
  507.         pidfd = open(pidfile, O_RDWR | O_CREAT, 0644);
  508.     }
  509.  
  510.     if (pidfd < 0) {
  511.         syslog(LOG_ERR, "open of pid file failed: %s", strerror(errno));
  512.         return -1;
  513.     }
  514.  
  515. #ifndef AMIGA
  516. #ifdef HAVE_FLOCK
  517.     while (flock(pidfd, LOCK_EX)) {
  518.         syslog(LOG_ERR, "sleeping: flock of pid file failed: %s",
  519. #else 
  520.     arg.l_type = F_WRLCK;
  521.     arg.l_whence = arg.l_start = arg.l_len = 0;
  522.     while ( -1 == fcntl( pidfd, F_SETLK, &arg) ) {
  523.         syslog(LOG_ERR, "sleeping: fcntl lock of pid file failed: %s",
  524. #endif
  525.                strerror(errno));
  526.         sleep(1);
  527.     }
  528. #endif
  529.     lseek(pidfd, 0, L_SET);
  530.  
  531.     count = 0;
  532.  
  533.     if (read(pidfd, buf, sizeof(buf)) == sizeof(buf)) {
  534.         for (which = 0; which < MAXUSERS; which++)
  535.             if (buf[which]
  536. #ifndef AMIGA
  537.  && !kill(buf[which], 0)
  538. #endif
  539.               )
  540.                 count++;
  541.     }
  542. #ifndef AMIGA
  543. #ifdef HAVE_FLOCK
  544.     flock(pidfd, LOCK_UN);
  545. #else
  546.     arg.l_type = F_UNLCK; arg.l_whence = arg.l_start = arg.l_len = 0;
  547.     fcntl(pidfd, F_SETLK, &arg);
  548. #endif
  549. #else
  550.     close(pidfd);
  551.     pidfd = -1;
  552. #endif
  553.     return (count);
  554. }
  555.  
  556. /*************************************************************************/
  557. /* FUNCTION  : acl_join                                                  */
  558. /* PURPOSE   : Add the current process to the list of processes in the   */
  559. /*             specified class.                                          */
  560. /* ARGUMENTS : The name of the class to join                             */
  561. /*************************************************************************/
  562.  
  563. void
  564. acl_join(char *class)
  565. {
  566.     int which,
  567.       avail;
  568.     pid_t buf[MAXUSERS];
  569.     char pidfile[MAXPATHLEN];
  570.     pid_t procid;
  571. #if !defined(HAVE_FLOCK) && !defined(AMIGA)
  572.     struct flock arg;
  573. #endif
  574.  
  575.     /* 
  576.      * if pidfd was not opened previously... 
  577.      * pidfd must stay open after the chroot(~ftp)  
  578.      */
  579.  
  580.     sprintf(pidfile, _PATH_PIDNAMES, class);
  581.  
  582.     if (pidfd < 0) {
  583.         pidfd = open(pidfile, O_RDWR | O_CREAT, 0644);
  584.     }
  585.  
  586.     if (pidfd < 0) {
  587.         syslog(LOG_ERR, "open of pid file failed: %s", strerror(errno));
  588.         return;
  589.     }
  590.  
  591. #ifndef AMIGA
  592. #ifdef HAVE_FLOCK
  593.     while (flock(pidfd, LOCK_EX)) {
  594.         syslog(LOG_ERR, "sleeping: flock of pid file failed: %s",
  595. #else 
  596.     arg.l_type = F_WRLCK;
  597.     arg.l_whence = arg.l_start = arg.l_len = 0;
  598.     while ( -1 == fcntl( pidfd, F_SETLK, &arg) ) {
  599.         syslog(LOG_ERR, "sleeping: fcntl lock of pid file failed: %s",
  600. #endif
  601.                strerror(errno));
  602.         sleep(1);
  603.     }
  604. #endif
  605.  
  606.     procid = getpid();
  607.  
  608.     lseek(pidfd, 0, L_SET);
  609.     if (read(pidfd, buf, sizeof(buf)) < sizeof(buf))
  610.         for (which = 0; which < MAXUSERS; buf[which++] = 0)
  611.             continue;
  612.  
  613.     avail = 0;
  614.     for (which = 0; which < MAXUSERS; which++) {
  615.         if ((buf[which] == 0)
  616. #ifndef AMIGA
  617.  || (kill(buf[which], 0) == -1)
  618. #endif
  619.            ) {
  620.             avail = which;
  621.             buf[which] = 0;
  622.         } else if (buf[which] == procid) {
  623.             /* already exists in pid file... */
  624. #ifndef AMIGA
  625. #ifdef HAVE_FLOCK
  626.             flock(pidfd, LOCK_UN);
  627. #else
  628.             arg.l_type = F_UNLCK; arg.l_whence = arg.l_start = arg.l_len = 0; 
  629.             fcntl(pidfd, F_SETLK, &arg);
  630. #endif
  631. #else
  632.             close(pidfd);
  633.             pidfd = -1;
  634. #endif
  635.             return;
  636.         }
  637.     }
  638.  
  639.     buf[avail] = procid;
  640.  
  641.     lseek(pidfd, 0, L_SET);
  642.     write(pidfd, buf, sizeof(buf));
  643. #ifndef AMIGA
  644. #ifdef HAVE_FLOCK
  645.     flock(pidfd, LOCK_UN);
  646. #else
  647.     arg.l_type = F_UNLCK; arg.l_whence = arg.l_start = arg.l_len = 0;
  648.     fcntl(pidfd, F_SETLK, &arg);
  649. #endif
  650. #else
  651.     close(pidfd);
  652.     pidfd = -1;
  653. #endif
  654.  
  655. }
  656.  
  657. /*************************************************************************/
  658. /* FUNCTION  : acl_remove                                                */
  659. /* PURPOSE   : remove the current process to the list of processes in    */
  660. /*             the specified class.                                      */
  661. /* ARGUMENTS : The name of the class to remove                           */
  662. /*************************************************************************/
  663.  
  664. void
  665. acl_remove()
  666. {
  667.     char class[1024];
  668.     int which,
  669.       avail;
  670.     pid_t buf[MAXUSERS];
  671.     char pidfile[MAXPATHLEN];
  672.     pid_t procid;
  673. #if !defined(HAVE_FLOCK) && !defined(AMIGA)
  674.     struct flock arg;
  675. #endif
  676.  
  677.     if (!acl_getclass(class)) {
  678.         return;
  679.     }
  680.  
  681.     /* 
  682.      * if pidfd was not opened previously... 
  683.      * pidfd must stay open after the chroot(~ftp)  
  684.      */
  685.  
  686.     sprintf(pidfile, _PATH_PIDNAMES, class);
  687.  
  688.     if (pidfd < 0) {
  689.         pidfd = open(pidfile, O_RDWR | O_CREAT, 0644);
  690.     }
  691.  
  692.     if (pidfd < 0) {
  693.         syslog(LOG_ERR, "open of pid file failed: %s", strerror(errno));
  694.         return;
  695.     }
  696.  
  697. #ifndef AMIGA
  698. #ifdef HAVE_FLOCK
  699.     while (flock(pidfd, LOCK_EX)) {
  700.         syslog(LOG_ERR, "sleeping: flock of pid file failed: %s",
  701. #else 
  702.     arg.l_type = F_WRLCK;
  703.     arg.l_whence = arg.l_start = arg.l_len = 0;
  704.     while ( -1 == fcntl( pidfd, F_SETLK, &arg) ) {
  705.         syslog(LOG_ERR, "sleeping: fcntl lock of pid file failed: %s",
  706. #endif
  707.                strerror(errno));
  708.         sleep(1);
  709.     }
  710. #endif
  711.  
  712.     procid = getpid();
  713.  
  714.     lseek(pidfd, 0, L_SET);
  715.     if (read(pidfd, buf, sizeof(buf)) < sizeof(buf))
  716.         for (which = 0; which < MAXUSERS; buf[which++] = 0)
  717.             continue;
  718.  
  719.     avail = 0;
  720.     for (which = 0; which < MAXUSERS; which++) {
  721.         if ((buf[which] == 0)
  722. #ifndef AMIGA
  723.  || (kill(buf[which], 0) == -1)
  724. #endif
  725.            ) {
  726.             avail = which;
  727.             buf[which] = 0;
  728.         } else if (buf[which] == procid) {
  729.             buf[which] = 0;
  730.         }
  731.     }
  732.  
  733.     lseek(pidfd, 0, L_SET);
  734.     write(pidfd, buf, sizeof(buf));
  735. #ifndef AMIGA
  736. #ifdef HAVE_FLOCK
  737.     flock(pidfd, LOCK_UN);
  738. #else
  739.     arg.l_type = F_UNLCK; arg.l_whence = arg.l_start = arg.l_len = 0;
  740.     fcntl(pidfd, F_SETLK, &arg);
  741. #endif
  742. #endif
  743.  
  744.     close(pidfd);
  745.     pidfd = -1;
  746. }
  747.  
  748. /*************************************************************************/
  749. /* FUNCTION  : pr_mesg                                                   */
  750. /* PURPOSE   : Display a message to the user                             */
  751. /* ARGUMENTS : message code, name of file to display                     */
  752. /*************************************************************************/
  753.  
  754. int
  755. pr_mesg(int msgcode, char *msgfile)
  756. {
  757.     FILE *infile;
  758.     char inbuf[1024],
  759.       outbuf[1024],
  760.      *cr;
  761.  
  762.     if (msgfile && strlen(msgfile) > 0) {
  763.         infile = fopen(msgfile, "r");
  764.         if (infile) {
  765.             while (fgets(inbuf, 255, infile) != NULL) {
  766.                 if ((cr = strchr(inbuf, '\n')) != NULL)
  767.                     *cr = '\0';
  768.                 msg_massage(inbuf, outbuf);
  769.                 lreply(msgcode, "%s", outbuf);
  770.             }
  771.             fclose(infile);
  772.         }
  773.     }
  774. }
  775.  
  776. /*************************************************************************/
  777. /* FUNCTION  : access_init                                               */
  778. /* PURPOSE   : Read and parse the access lists to set things up          */
  779. /* ARGUMENTS : none                                                      */
  780. /*************************************************************************/
  781.  
  782. void
  783. access_init(void)
  784. {
  785.     struct aclmember *entry;
  786.  
  787.     if (!readacl(_PATH_FTPACCESS))
  788.         return;
  789.     (void) parseacl();
  790.  
  791.     Shutdown[0] = '\0';
  792.     entry = (struct aclmember *) NULL;
  793.     if (getaclentry("shutdown", &entry) && ARG0 != NULL)
  794.         (void) strncpy(Shutdown, ARG0, sizeof(Shutdown));
  795.  
  796. }
  797.  
  798. /*************************************************************************/
  799. /* FUNCTION  : access_ok                                                 */
  800. /* PURPOSE   : Check the anonymous FTP access lists to see if this       */
  801. /*             access is permitted.                                      */
  802. /* ARGUMENTS : none                                                      */
  803. /*************************************************************************/
  804.  
  805. int
  806. access_ok(int msgcode)
  807. {
  808.     char class[1024],
  809.       msgfile[MAXPATHLEN];
  810.     int limit;
  811.  
  812.     if (!use_accessfile)
  813.         return (1);
  814.  
  815.     if (aclbuf == NULL) {
  816.         syslog(LOG_NOTICE, 
  817.         "ACCESS DENIED (error reading access file) TO %s [%s]",
  818.                  remotehost, remoteaddr);
  819.         return (0);
  820.     }
  821.     if (acl_deny(msgfile)) {
  822.         pr_mesg(msgcode, msgfile);
  823.         syslog(LOG_NOTICE, "ACCESS DENIED (deny command) TO %s [%s]",
  824.                remotehost, remoteaddr);
  825.         return (0);
  826.     }
  827.     /* if user is not in any class, deny access */
  828.     if (!acl_getclass(class)) {
  829.         syslog(LOG_NOTICE, "ACCESS DENIED (not in any class) TO %s [%s]",
  830.                remotehost, remoteaddr);
  831.         return (0);
  832.     }
  833.     /* if no limits defined, no limits apply -- access OK */
  834.     limit = acl_getlimit(class, msgfile);
  835.  
  836.     if ((limit == -1) || (acl_countusers(class) < limit)) {
  837.         acl_join(class);
  838.         return (1);
  839.     } else {
  840.         syslog(LOG_NOTICE, "ACCESS DENIED (user limit %d; class %s) TO %s [%s]",
  841.                limit, class, remotehost, remoteaddr);
  842.         pr_mesg(msgcode, msgfile);
  843.         return (-1);
  844.     }
  845.  
  846.     /* NOTREACHED */
  847. }
  848.